use std::io;
use std::io::Write;
use std::sync::{Arc, Mutex, OnceLock};
use std::thread;

//通常静态变量会定义在全局作用域中，并且通常是大写字母开头的常量命名规则。
static ARC_AGE: OnceLock<Arc<Mutex<u32>>> = OnceLock::new();
static mut SIGN: u32 = 0;

//允许指向静态变量的共享引用，不要一直提示了
#[allow(static_mut_refs)]
fn main() {
    ARC_AGE.get_or_init(|| Arc::new(Mutex::new(18))); // 初始年龄设为18
    print!("请输入线程数量:"); //注意print!宏不会刷新输出流,除非有换行符，所以需要手动刷新输出流
    std::io::stdout().flush().unwrap();
    let thread_qty = read_thread_qty();
    // 重置SIGN为0，准备执行新的示例
    println!("\n现在开始演示ARC_AGE的并行修改:");

    // 执行新的示例
    change_static_in_parallel2(thread_qty);

    let age = ARC_AGE.get().unwrap();
    println!("主线程-ARC_AGE现在的值: {}", *age.lock().unwrap());
    println!("--- 预备.... 开始!!! ");

    unsafe {
        SIGN = 1;
    }

    // 在主线程中循环打印ARC_AGE的值，直到其值达到目标值
    let target_age = 18 + thread_qty;
    while *age.lock().unwrap() < target_age {
        println!("主线程-ARC_AGE现在的值: {}", *age.lock().unwrap());
        thread::sleep(std::time::Duration::from_millis(5));
    }
    println!("主线程-ARC_AGE最后的值: {}", *age.lock().unwrap());
}

/**
 * 使用Arc演示多线程下对全局变量的访问
 */
fn change_static_in_parallel2(thread_qty: u32) {
    let age = ARC_AGE.get().unwrap().clone();
    let mut handles = vec![];

    for _ in 0..thread_qty {
        let age = age.clone();
        let handle = thread::spawn(move || {
            //等待主线程通知开始执行子线程任务
            unsafe {
                while SIGN == 0 {
                    thread::sleep(std::time::Duration::from_millis(50));
                }
            }
            let mut current_age = age.lock().unwrap();
            *current_age += 1;
            println!(
                "----子线程{:?}将年龄+1得到{}",
                thread::current().id(),
                *current_age
            );
        });
        handles.push(handle);
    }
    //此处不要join,因为它要等待SIGN=1后才执行，且就算SIGN=1，也会被主线程阻塞
}

fn read_thread_qty() -> u32 {
    let mut gts = String::new();
    io::stdin().read_line(&mut gts).expect("读取失败");
    let gts: u32 = gts.trim().parse().expect("请输入一个数字");
    return gts;
}
